package system

import (
	"github.com/fatih/structs"
	"github.com/spf13/cast"
	"gorm.io/gorm"
	"seven-admin/app/admin/schemas/query"
	"seven-admin/app/admin/schemas/req"
	"seven-admin/app/admin/schemas/resp"
	"seven-admin/app/collection/system"
	"seven-admin/core"
	"seven-admin/core/config"
	"seven-admin/core/response"
	"seven-admin/util"
	"strconv"
	"strings"
	"time"
)

type AuthTenantService interface {
	All(auth *req.AuthReq) (res []resp.SystemAuthTenantResp, e error)
	List(page req.PageReq, auth *req.AuthReq) (res response.PageResp, e error)
	Detail(id uint, auth *req.AuthReq) (res resp.SystemAuthTenantResp, e error)
	Add(addReq req.SystemAuthTenantAddReq, auth *req.AuthReq) (e error)
	Edit(editReq req.SystemAuthTenantEditReq, auth *req.AuthReq) (e error)
	Del(id uint, auth *req.AuthReq) (e error)
}

// NewAuthTenantService 初始化
func NewAuthTenantService(db *gorm.DB, permSrv AuthTenantPermService) AuthTenantService {
	return &authTenantService{db: db, permSrv: permSrv}
}

// authTenantService 系统角色服务实现类
type authTenantService struct {
	db      *gorm.DB
	permSrv AuthTenantPermService
}

// All 角色所有
func (r authTenantService) All(auth *req.AuthReq) (res []resp.SystemAuthTenantResp, e error) {
	var tenants []system.AuthTenant
	sql := query.AuthQuery(r.db, auth)
	err := sql.Order("id asc").Find(&tenants).Error
	if e = response.CheckErr(err, "All Find err"); e != nil {
		return
	}
	response.Copy(&res, tenants)
	return
}

// List 根据角色ID获取菜单ID
func (r authTenantService) List(page req.PageReq, auth *req.AuthReq) (res response.PageResp, e error) {
	limit := page.PageSize
	offset := page.PageSize * (page.PageNo - 1)
	tenantModel := query.AuthQuery(r.db.Model(&system.AuthTenant{}), auth)

	var count int64
	err := tenantModel.Count(&count).Error
	if e = response.CheckErr(err, "List Count err"); e != nil {
		return
	}
	var tenants []system.AuthTenant
	err = tenantModel.Limit(limit).Offset(offset).Order("id asc").Find(&tenants).Error
	if e = response.CheckErr(err, "List Find err"); e != nil {
		return
	}
	var tenantResp []resp.SystemAuthTenantResp
	response.Copy(&tenantResp, tenants)
	for i := 0; i < len(tenantResp); i++ {
		tenantResp[i].Menus = []uint{}
		tenantResp[i].Member = r.getMemberCnt(tenantResp[i].ID, auth)
	}
	return response.PageResp{
		PageNo:   page.PageNo,
		PageSize: page.PageSize,
		Count:    count,
		Lists:    tenantResp,
	}, nil
}

// Detail 角色详情
func (r authTenantService) Detail(id uint, auth *req.AuthReq) (res resp.SystemAuthTenantResp, e error) {
	var tenant system.AuthTenant
	sql := query.AuthQuery(r.db, auth)
	err := sql.Where("id = ?", id).Limit(1).First(&tenant).Error
	if e = response.CheckErrDBNotRecord(err, "角色已不存在!"); e != nil {
		return
	}
	if e = response.CheckErr(err, "Detail First err"); e != nil {
		return
	}
	response.Copy(&res, tenant)
	res.Member = r.getMemberCnt(tenant.ID, auth)
	res.Menus, e = r.permSrv.SelectMenuIdsByTenantId(tenant.ID, auth)
	return
}

// getMemberCnt 根据角色ID获取成员数量
func (r authTenantService) getMemberCnt(tenantId uint, auth *req.AuthReq) (count int64) {
	sql := query.AuthQuery(r.db.Model(&system.AuthAdmin{}), auth)
	sql.Where(
		"tenant_id = ?", tenantId).Count(&count)
	return
}

// Add 新增角色
func (r authTenantService) Add(addReq req.SystemAuthTenantAddReq, auth *req.AuthReq) (e error) {
	var tenant system.AuthTenant
	sql := query.AuthQuery(r.db, auth)
	if r := sql.Where("name = ?", strings.Trim(addReq.Name, " ")).Limit(1).First(&tenant); r.RowsAffected > 0 {
		return response.AssertArgumentError.Make("角色名称已存在!")
	}
	response.Copy(&tenant, addReq)
	tenant.Name = strings.Trim(addReq.Name, " ")
	// 事务
	err := r.db.Transaction(func(tx *gorm.DB) error {
		txErr := tx.Create(&tenant).Error
		var te error
		if te = response.CheckErr(txErr, "Add Create in tx err"); te != nil {
			return te
		}
		te = r.permSrv.BatchSaveByMenuIds(tenant.ID, addReq.MenuIds, tx, auth)
		if te = response.CheckErr(txErr, "Add Create in tx err"); te != nil {
			return te
		}
		ta := r.newTenantConfig(tx, &tenant)
		return ta
	})
	e = response.CheckErr(err, "Add Transaction err")
	return
}

// Edit 编辑角色
func (r authTenantService) Edit(editReq req.SystemAuthTenantEditReq, auth *req.AuthReq) (e error) {
	sql := query.AuthQuery(r.db, auth)
	err := sql.Where("id = ?", editReq.ID).Limit(1).First(&system.AuthTenant{}).Error
	if e = response.CheckErrDBNotRecord(err, "角色已不存在!"); e != nil {
		return
	}
	if e = response.CheckErr(err, "Edit First err"); e != nil {
		return
	}
	var tenant system.AuthTenant
	if r := sql.Where("id != ? AND name = ?", editReq.ID, strings.Trim(editReq.Name, " ")).Limit(1).First(&tenant); r.RowsAffected > 0 {
		return response.AssertArgumentError.Make("角色名称已存在!")
	}
	tenant.ID = editReq.ID
	tenantMap := structs.Map(editReq)
	delete(tenantMap, "ID")
	delete(tenantMap, "MenuIds")
	tenantMap["Name"] = strings.Trim(editReq.Name, " ")
	if !auth.SoftSuperAdmin && !auth.IsSuperAdmin {
		return response.AssertArgumentError.Make("你没有权限编辑此角色!")
	}
	// 事务
	err = r.db.Transaction(func(tx *gorm.DB) error {
		txErr := tx.Model(&tenant).Updates(tenantMap).Error
		var te error
		if te = response.CheckErr(txErr, "Edit Updates in tx err"); te != nil {
			return te
		}
		if te = r.permSrv.BatchDeleteByTenantId(editReq.ID, tx, auth); te != nil {
			return te
		}
		if te = r.permSrv.BatchSaveByMenuIds(editReq.ID, editReq.MenuIds, tx, auth); te != nil {
			return te
		}
		//te = r.permSrv.CacheRoleMenusByTenantId(editReq.ID)
		return te
	})
	e = response.CheckErr(err, "Edit Transaction err")
	return
}

// Del 删除角色
func (r authTenantService) Del(id uint, auth *req.AuthReq) (e error) {
	sql := query.AuthQuery(r.db, auth)
	err := sql.Where("id = ?", id).Limit(1).First(&system.AuthTenant{}).Error
	if e = response.CheckErrDBNotRecord(err, "角色已不存在!"); e != nil {
		return
	}
	if e = response.CheckErr(err, "Del First err"); e != nil {
		return
	}
	if r := sql.Where("tenant_id = ?", id).Limit(1).Find(&system.AuthAdmin{}); r.RowsAffected > 0 {
		return response.AssertArgumentError.Make("角色已被管理员使用,请先移除!")
	}
	if !auth.SoftSuperAdmin && !auth.IsSuperAdmin {
		return response.AssertArgumentError.Make("你没有权限删除此角色!")
	}
	// 事务
	err = r.db.Transaction(func(tx *gorm.DB) error {
		txErr := tx.Delete(&system.AuthTenant{}, "id = ?", id).Error
		var te error
		if te = response.CheckErr(txErr, "Del Delete in tx err"); te != nil {
			return te
		}
		errs := tx.Delete(&system.Config{}, "tenant_id = ?", id).Error
		if te = response.CheckErr(errs, "Del Delete in tx err"); te != nil {
			return te
		}
		if te = r.permSrv.BatchDeleteByTenantId(id, tx, auth); te != nil {
			return te
		}
		util.RedisUtil.HDel(config.AdminConfig.BackstageRolesKey, strconv.FormatUint(uint64(id), 10))
		return nil
	})
	e = response.CheckErr(err, "Del Transaction err")
	return
}

// newTenantConfig 初始化
func (r authTenantService) newTenantConfig(tx *gorm.DB, tenant *system.AuthTenant) error {
	model := system.Config{}
	tbName := core.DBTableName(model)
	timeNow := time.Now().Unix()
	sql := `
INSERT INTO ` + tbName + ` ("create_time", "update_time", "type", "name", "value", "tenant_id") VALUES (` + cast.ToString(timeNow) + `, ` + cast.ToString(timeNow) + `, 'website', 'name', '` + tenant.Name + `', ` + cast.ToString(tenant.ID) + `);
INSERT INTO ` + tbName + ` ("create_time", "update_time", "type", "name", "value", "tenant_id") VALUES (` + cast.ToString(timeNow) + `, ` + cast.ToString(timeNow) + `, 'website', 'logo', '/image/20241707/efcdbf2b41df4e2cbd2b5d8af4be1c44.png', ` + cast.ToString(tenant.ID) + `);
INSERT INTO ` + tbName + ` ("create_time", "update_time", "type", "name", "value", "tenant_id") VALUES (` + cast.ToString(timeNow) + `, ` + cast.ToString(timeNow) + `, 'website', 'favicon', '/image/20241707/efcdbf2b41df4e2cbd2b5d8af4be1c44.png', ` + cast.ToString(tenant.ID) + `);
INSERT INTO ` + tbName + ` ("create_time", "update_time", "type", "name", "value", "tenant_id") VALUES (` + cast.ToString(timeNow) + `, ` + cast.ToString(timeNow) + `, 'website', 'backdrop', '/image/20241707/abb1d3739700419e98c6f1e5a3c124a7.png', ` + cast.ToString(tenant.ID) + `);
INSERT INTO ` + tbName + ` ("create_time", "update_time", "type", "name", "value", "tenant_id") VALUES (` + cast.ToString(timeNow) + `, ` + cast.ToString(timeNow) + `, 'website', 'copyright', '[{
	"name": "` + tenant.Name + `  浙ICP备00000000号-1",
	"link": "https://beian.miit.gov.cn/"
}]', ` + cast.ToString(tenant.ID) + `);
INSERT INTO ` + tbName + ` ("create_time", "update_time", "type", "name", "value", "tenant_id") VALUES (` + cast.ToString(timeNow) + `, ` + cast.ToString(timeNow) + `, 'website', 'shopName', '` + tenant.Name + `', ` + cast.ToString(tenant.ID) + `);
INSERT INTO ` + tbName + ` ("create_time", "update_time", "type", "name", "value", "tenant_id") VALUES (` + cast.ToString(timeNow) + `, ` + cast.ToString(timeNow) + `, 'website', 'shopLogo', '/image/20241707/abb1d3739700419e98c6f1e5a3c124a7.png', ` + cast.ToString(tenant.ID) + `);
INSERT INTO ` + tbName + ` ("create_time", "update_time", "type", "name", "value", "tenant_id") VALUES (` + cast.ToString(timeNow) + `, ` + cast.ToString(timeNow) + `, 'protocol', 'service', '{"name":"用户使用条款","content":"用户使用条款"}', ` + cast.ToString(tenant.ID) + `);
INSERT INTO ` + tbName + ` ("create_time", "update_time", "type", "name", "value", "tenant_id") VALUES (` + cast.ToString(timeNow) + `, ` + cast.ToString(timeNow) + `, 'protocol', 'privacy', '{"name":"隐私声明","content":"隐私声明"}', ` + cast.ToString(tenant.ID) + `);
INSERT INTO ` + tbName + ` ("create_time", "update_time", "type", "name", "value", "tenant_id") VALUES (` + cast.ToString(timeNow) + `, ` + cast.ToString(timeNow) + `, 'tabbar', 'style', '{"defaultColor":"#4A5DFF","selectedColor":"#EA5455"}', ` + cast.ToString(tenant.ID) + `);
INSERT INTO ` + tbName + ` ("create_time", "update_time", "type", "name", "value", "tenant_id") VALUES (` + cast.ToString(timeNow) + `, ` + cast.ToString(timeNow) + `, 'search', 'isHotSearch', '0', ` + cast.ToString(tenant.ID) + `);
	`
	return tx.Exec(sql).Error
}
